home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / programming / other / scrollingtricks / source / scroller_xyunlimited / main.c < prev    next >
C/C++ Source or Header  |  1999-04-19  |  25KB  |  1,271 lines

  1. #include <exec/exec.h>
  2. #include <dos/dos.h>
  3. #include <intuition/intuition.h>
  4. #include <graphics/gfx.h>
  5. #include <hardware/custom.h>
  6. #include <hardware/dmabits.h>
  7.  
  8. #ifdef __MAXON__
  9. #include <pragma/exec_lib.h>
  10. #include <pragma/dos_lib.h>
  11. #include <pragma/graphics_lib.h>
  12. #include <pragma/intuition_lib.h>
  13. #else
  14. #include <proto/exec.h>
  15. #include <proto/dos.h>
  16. #include <proto/graphics.h>
  17. #include <proto/intuition.h>
  18. #endif
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22.  
  23. #include "hardware.h"
  24. #include "cop.h"
  25. #include "map.h"
  26.  
  27.  
  28. #define ARG_TEMPLATE "SPEED/S,NTSC/S,HOW/S,FMODE/N/K"
  29. #define ARG_SPEED 0
  30. #define ARG_NTSC  1
  31. #define ARG_HOW   2
  32. #define ARG_FMODE 3
  33. #define NUM_ARGS  4
  34.  
  35. #define MAPNAME        "maps/scroller.raw"
  36. #define BLOCKSNAME    "blocks/demoblocks.raw"
  37.  
  38. #define SCREENWIDTH  320
  39. #define SCREENHEIGHT 256
  40. #define EXTRAWIDTH  64
  41. #define EXTRAHEIGHT 32
  42. #define SCREENBYTESPERROW (SCREENWIDTH / 8)
  43.  
  44. #define BITMAPWIDTH (SCREENWIDTH + EXTRAWIDTH)
  45. #define BITMAPBYTESPERROW (BITMAPWIDTH / 8)
  46. #define BITMAPHEIGHT (SCREENHEIGHT + EXTRAHEIGHT)
  47.  
  48. #define BLOCKSWIDTH 320
  49. #define BLOCKSHEIGHT 200
  50. #define BLOCKSDEPTH 4
  51. #define BLOCKSCOLORS (1L << BLOCKSDEPTH)
  52. #define BLOCKWIDTH 16
  53. #define BLOCKHEIGHT 16
  54. #define BLOCKSBYTESPERROW (BLOCKSWIDTH / 8)
  55. #define BLOCKSPERROW (BLOCKSWIDTH / BLOCKWIDTH)
  56.  
  57. #define NUMSTEPS_X BLOCKWIDTH
  58. #define NUMSTEPS_Y BLOCKHEIGHT
  59.  
  60. #define BITMAPBLOCKSPERROW (BITMAPWIDTH / BLOCKWIDTH)
  61. #define BITMAPBLOCKSPERCOL (BITMAPHEIGHT / BLOCKHEIGHT)
  62.  
  63. #define VISIBLEBLOCKSX (SCREENWIDTH / BLOCKWIDTH)
  64. #define VISIBLEBLOCKSY (SCREENHEIGHT / BLOCKHEIGHT)
  65.  
  66. #define BITMAPPLANELINES (BITMAPHEIGHT * BLOCKSDEPTH)
  67. #define BLOCKPLANELINES  (BLOCKHEIGHT * BLOCKSDEPTH)
  68.  
  69. #define DIWSTART 0x2981
  70. #define DIWSTOP  0x29C1
  71.  
  72. #define PALSIZE (BLOCKSCOLORS * 2)
  73. #define BLOCKSFILESIZE (BLOCKSWIDTH * BLOCKSHEIGHT * BLOCKSPLANES / 8 + PALSIZE)
  74.  
  75. #define DIRECTION_IGNORE 0
  76. #define DIRECTION_LEFT   1
  77. #define DIRECTION_RIGHT  2
  78.  
  79. // calculate how many times (steps) y-scrolling needs to
  80. // blit two blocks instead of one block to make sure a
  81. // complete row is blitted after 16 pixels of y-scrolling
  82. //
  83. // x * 2 + (16 - x) = BITMAPBLOCKSPERROW
  84. // 2x + 16 - x = BITMAPBLOCKSPERROW
  85. // x = BITMAPBLOCKSPERROW - 16
  86.  
  87. #define TWOBLOCKS (BITMAPBLOCKSPERROW - NUMSTEPS_Y)
  88. #define TWOBLOCKSTEP TWOBLOCKS
  89.  
  90. struct IntuitionBase *IntuitionBase;
  91. struct GfxBase *GfxBase;
  92. struct Screen *scr;
  93. struct RastPort *ScreenRastPort;
  94. struct BitMap *BlocksBitmap,*ScreenBitmap;
  95. struct RawMap *Map;
  96. UBYTE     *frontbuffer,*blocksbuffer;
  97.  
  98. WORD    mapposx,mapposy,videoposx,videoposy,block_videoposy;
  99. WORD    mapblockx,mapblocky,stepx,stepy;
  100. WORD    bitmapheight,bitplanemodulo;
  101.  
  102. WORD    *savewordpointer;
  103. WORD    saveword;
  104. BYTE    previous_xdirection;
  105.  
  106. LONG    mapwidth,mapheight;
  107. UBYTE *mapdata;
  108.  
  109. UWORD    colors[BLOCKSCOLORS];
  110.  
  111. LONG    Args[NUM_ARGS];
  112.  
  113. BOOL    option_ntsc,option_how,option_speed;
  114. WORD    option_fetchmode;
  115.  
  116. BPTR    MyHandle;
  117. char    s[256];
  118.  
  119. #if EXTRAWIDTH == 32
  120.  
  121.     // bitmap width aligned to 32 Pixels
  122.     #define MAX_FETCHMODE 2
  123.     #define MAX_FETCHMODE_S "2"
  124.  
  125. #elif EXTRAWIDTH == 64
  126.  
  127.     // bitmap width aligned to 64 Pixels
  128.     #define MAX_FETCHMODE 3
  129.     #define MAX_FETCHMODE_S "3"
  130.  
  131. #else
  132.  
  133.     // bad extrawidth
  134.     #error "EXTRAWIDTH must be either 32 or 64"
  135.  
  136. #endif
  137.  
  138. struct FetchInfo
  139. {
  140.     WORD    ddfstart;
  141.     WORD    ddfstop;
  142.     WORD    modulooffset;
  143.     WORD    bitmapoffset;
  144.     WORD    scrollpixels;
  145. } fetchinfo [] =
  146. {
  147.     {0x30,0xD0,2,0,16},    /* normal         */
  148.     {0x28,0xC8,4,16,32},    /* BPL32          */
  149.     {0x28,0xC8,4,16,32},    /* BPAGEM         */
  150.     {0x18,0xB8,8,48,64}    /* BPL32 + BPAGEM */
  151. };
  152.  
  153. /********************* MACROS ***********************/
  154.  
  155. #define ROUND2BLOCKWIDTH(x)  ((x) & ~(BLOCKWIDTH - 1))
  156. #define ROUND2BLOCKHEIGHT(x) ((x) & ~(BLOCKHEIGHT - 1))
  157.  
  158. #define ADJUSTDESTCOORDS(x,y)         \
  159.     if (x >= BITMAPWIDTH)                \
  160.     {                                            \
  161.         x -= BITMAPWIDTH;                    \
  162.         y++;                                    \
  163.         if (y >= BITMAPPLANELINES)        \
  164.         {                                        \
  165.             y -= BITMAPPLANELINES;        \
  166.         }                                        \
  167.     }
  168.  
  169. /************* SETUP/CLEANUP ROUTINES ***************/
  170.  
  171. static void Cleanup (char *msg)
  172. {
  173.     WORD rc;
  174.     
  175.     if (msg)
  176.     {
  177.         printf("Error: %s\n",msg);
  178.         rc = RETURN_WARN;
  179.     } else {
  180.         rc = RETURN_OK;
  181.     }
  182.  
  183.     if (scr) CloseScreen(scr);
  184.  
  185.     if (ScreenBitmap)
  186.     {
  187.         WaitBlit();
  188.         FreeBitMap(ScreenBitmap);
  189.     }
  190.  
  191.     if (BlocksBitmap)
  192.     {
  193.         WaitBlit();
  194.         FreeBitMap(BlocksBitmap);
  195.     }
  196.  
  197.     if (Map) FreeVec(Map);
  198.     if (MyHandle) Close(MyHandle);
  199.  
  200.     if (GfxBase) CloseLibrary((struct Library *)GfxBase);
  201.     if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
  202.  
  203.     exit(rc);
  204. }
  205.  
  206. static void OpenLibs(void)
  207. {
  208.     if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",39)))
  209.     {
  210.         Cleanup("Can't open intuition.library V39!");
  211.     }
  212.     
  213.     if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39)))
  214.     {
  215.         Cleanup("Can't open graphics.library V39!");
  216.     }
  217. }
  218.  
  219. static void GetArguments(void)
  220. {
  221.     struct RDArgs *MyArgs;
  222.  
  223.     if (!(MyArgs = ReadArgs(ARG_TEMPLATE,Args,0)))
  224.     {
  225.         Fault(IoErr(),0,s,255);
  226.         Cleanup(s);
  227.     }
  228.  
  229.     if (Args[ARG_SPEED]) option_speed = TRUE;
  230.     if (Args[ARG_NTSC]) option_ntsc = TRUE;
  231.     if (Args[ARG_HOW])
  232.     {
  233.         option_how = TRUE;
  234.         option_speed = FALSE;
  235.     }
  236.  
  237.     if (Args[ARG_FMODE])
  238.     {
  239.         option_fetchmode = *(LONG *)Args[ARG_FMODE];
  240.     }
  241.  
  242.     FreeArgs(MyArgs);
  243.     
  244.     if (option_fetchmode < 0 || option_fetchmode > MAX_FETCHMODE)
  245.     {
  246.         Cleanup("Invalid fetch mode. Must be 0 .. " MAX_FETCHMODE_S "!");
  247.     }
  248.  
  249. }
  250.  
  251. static void OpenMap(void)
  252. {
  253.     LONG l;
  254.  
  255.     if (!(MyHandle = Open(MAPNAME,MODE_OLDFILE)))
  256.     {
  257.         Fault(IoErr(),0,s,255);
  258.         Cleanup(s);
  259.     }
  260.     
  261.     Seek(MyHandle,0,OFFSET_END);
  262.     l = Seek(MyHandle,0,OFFSET_BEGINNING);
  263.  
  264.     if (!(Map = AllocVec(l,MEMF_PUBLIC)))
  265.     {
  266.         Cleanup("Out of memory!");
  267.     }
  268.     
  269.     if (Read(MyHandle,Map,l) != l)
  270.     {
  271.         Fault(IoErr(),0,s,255);
  272.         Cleanup(s);
  273.     }
  274.     
  275.     Close(MyHandle);MyHandle = 0;
  276.     
  277.     mapdata = Map->data;
  278.     mapwidth = Map->mapwidth;
  279.     mapheight = Map->mapheight;
  280. }
  281.  
  282. static void OpenBlocks(void)
  283. {
  284.     LONG l;
  285.  
  286.     if (!(BlocksBitmap = AllocBitMap(BLOCKSWIDTH,
  287.                                                BLOCKSHEIGHT,
  288.                                                BLOCKSDEPTH,
  289.                                                BMF_STANDARD | BMF_INTERLEAVED,
  290.                                                0)))
  291.     {
  292.         Cleanup("Can't alloc blocks bitmap!");
  293.     }
  294.     
  295.     if (!(MyHandle = Open(BLOCKSNAME,MODE_OLDFILE)))
  296.     {
  297.         Fault(IoErr(),0,s,255);
  298.         Cleanup(s);
  299.     }
  300.     
  301.     if (Read(MyHandle,colors,PALSIZE) != PALSIZE)
  302.     {
  303.         Fault(IoErr(),0,s,255);
  304.         Cleanup(s);
  305.     }
  306.     
  307.     l = BLOCKSWIDTH * BLOCKSHEIGHT * BLOCKSDEPTH / 8;
  308.     
  309.     if (Read(MyHandle,BlocksBitmap->Planes[0],l) != l)
  310.     {
  311.         Fault(IoErr(),0,s,255);
  312.         Cleanup(s);
  313.     }
  314.     
  315.     Close(MyHandle);MyHandle = 0;
  316.     
  317.     blocksbuffer = BlocksBitmap->Planes[0];
  318. }
  319.  
  320. static void OpenDisplay(void)
  321. {    
  322.     struct DimensionInfo diminfo;
  323.     DisplayInfoHandle        dih;
  324.     ULONG                        modeid;
  325.     LONG                        l;
  326.     
  327.     bitmapheight = BITMAPHEIGHT + 3;
  328.  
  329.     if (!(ScreenBitmap = AllocBitMap(BITMAPWIDTH,bitmapheight,BLOCKSDEPTH,BMF_STANDARD | BMF_INTERLEAVED | BMF_CLEAR,0)))
  330.     {
  331.         Cleanup("Can't alloc screen bitmap!");
  332.     }
  333.  
  334.     frontbuffer = ScreenBitmap->Planes[0];
  335.     frontbuffer += (fetchinfo[option_fetchmode].bitmapoffset / 8);
  336.  
  337.     if (!(TypeOfMem(ScreenBitmap->Planes[0]) & MEMF_CHIP))
  338.     {
  339.         Cleanup("Screen bitmap is not in CHIP RAM!?? If you have a gfx card try disabling \"planes to fast\" or similiar options in your RTG system!");
  340.     }
  341.  
  342.     l = GetBitMapAttr(ScreenBitmap,BMA_FLAGS);
  343.     
  344.     if (!(GetBitMapAttr(ScreenBitmap,BMA_FLAGS) & BMF_INTERLEAVED))
  345.     {
  346.         Cleanup("Screen bitmap is not in interleaved format!??");
  347.     }
  348.     
  349.     if (option_how)
  350.     {
  351.         modeid = INVALID_ID;
  352.  
  353.         if ((dih = FindDisplayInfo(VGAPRODUCT_KEY)))
  354.         {
  355.             if (GetDisplayInfoData(dih,(APTR)&diminfo,sizeof(diminfo),DTAG_DIMS,0))
  356.             {
  357.                 if (diminfo.MaxDepth >= BLOCKSDEPTH) modeid = VGAPRODUCT_KEY;
  358.             }
  359.         }
  360.         if (modeid == INVALID_ID)
  361.         {
  362.             if (option_ntsc)
  363.             {
  364.                 modeid = NTSC_MONITOR_ID | HIRESLACE_KEY;
  365.             } else {
  366.                 modeid = PAL_MONITOR_ID | HIRESLACE_KEY;
  367.             }
  368.         }
  369.     } else {
  370.         if (option_ntsc)
  371.         {
  372.             modeid = NTSC_MONITOR_ID;
  373.         } else {
  374.             modeid = PAL_MONITOR_ID;
  375.         }
  376.     }
  377.  
  378.     if (!(scr = OpenScreenTags(0,SA_Width,BITMAPWIDTH,
  379.                                           SA_Height,bitmapheight,
  380.                                           SA_Depth,BLOCKSDEPTH,
  381.                                           SA_DisplayID,modeid,
  382.                                           SA_BitMap,ScreenBitmap,
  383.                                           option_how ? SA_Overscan : TAG_IGNORE,OSCAN_TEXT,
  384.                                           option_how ? SA_AutoScroll : TAG_IGNORE,TRUE,
  385.                                           SA_Quiet,TRUE,
  386.                                           TAG_DONE)))
  387.     {
  388.         Cleanup("Can't open screen!");
  389.     }
  390.  
  391.     if (scr->RastPort.BitMap->Planes[0] != ScreenBitmap->Planes[0])
  392.     {
  393.         Cleanup("Screen was not created with the custom bitmap I supplied!??");
  394.     }
  395.     
  396.     ScreenRastPort = &scr->RastPort;
  397.     
  398.     LoadRGB4(&scr->ViewPort,colors,BLOCKSCOLORS);
  399. }
  400.  
  401. static void InitCopperlist(void)
  402. {
  403.     WORD    *wp;
  404.     ULONG    plane,plane2;
  405.     LONG    l;
  406.  
  407.     WaitVBL();
  408.  
  409.     custom->dmacon = 0x7FFF;
  410.     custom->beamcon0 = option_ntsc ? 0 : DISPLAYPAL;
  411.  
  412.     CopFETCHMODE[1] = option_fetchmode;
  413.     
  414.     // bitplane control registers
  415.  
  416.     CopBPLCON0[1] = ((BLOCKSDEPTH * BPL0_BPU0_F) & BPL0_BPUMASK) +
  417.                          ((BLOCKSDEPTH / 8) * BPL0_BPU3_F) +
  418.                          BPL0_COLOR_F +
  419.                          (option_speed ? 0 : BPL0_USEBPLCON3_F);
  420.  
  421.     CopBPLCON1[1] = 0;
  422.  
  423.     CopBPLCON3[1] = BPLCON3_BRDNBLNK;
  424.  
  425.     // bitplane modulos
  426.  
  427.     l = BITMAPBYTESPERROW * BLOCKSDEPTH -
  428.          SCREENBYTESPERROW - fetchinfo[option_fetchmode].modulooffset;
  429.  
  430.     CopBPLMODA[1] = l;
  431.     CopBPLMODB[1] = l;
  432.     
  433.     CopVIDEOSPLITRESETMODULO[1] = l;
  434.     CopVIDEOSPLITRESETMODULO[3] = l;
  435.  
  436.     bitplanemodulo = l;
  437.  
  438.     // display window start/stop
  439.     
  440.     CopDIWSTART[1] = DIWSTART;
  441.     CopDIWSTOP[1] = DIWSTOP;
  442.     
  443.     // display data fetch start/stop
  444.     
  445.     CopDDFSTART[1] = fetchinfo[option_fetchmode].ddfstart;
  446.     CopDDFSTOP[1]  = fetchinfo[option_fetchmode].ddfstop;
  447.     
  448.     // plane pointers
  449.  
  450.     wp = CopPLANE1H;
  451.  
  452.     for(l = 0;l < BLOCKSDEPTH;l++)
  453.     {
  454.         plane = (ULONG)ScreenBitmap->Planes[l];
  455.         
  456.         wp[1] = plane >> 16;
  457.         wp[3] = plane & 0xFFFF;
  458.  
  459.         wp += 4;
  460.     }
  461.  
  462.     // Setup modulo trick
  463.  
  464.     plane = (ULONG)ScreenBitmap->Planes[0];
  465.  
  466.     plane2 = plane +
  467.                 (BITMAPHEIGHT - 1) * BITMAPBYTESPERROW * BLOCKSDEPTH +
  468.                 SCREENBYTESPERROW +
  469.                 fetchinfo[option_fetchmode].modulooffset;
  470.  
  471.     l = (plane - plane2) & 0xFFFF;
  472.  
  473.     CopVIDEOSPLITMODULO[1] = l;
  474.     CopVIDEOSPLITMODULO[3] = l;
  475.     
  476.     CopVIDEOSPLITMODULO[1] = l;
  477.     CopVIDEOSPLITMODULO[3] = l;
  478.  
  479.     /**/
  480.     
  481.     custom->intena = 0x7FFF;
  482.     
  483.     custom->dmacon = DMAF_SETCLR | DMAF_BLITTER | DMAF_COPPER | DMAF_RASTER | DMAF_MASTER;
  484.  
  485.     custom->cop2lc = (ULONG)CopperList;    
  486. };
  487.  
  488. /******************* SCROLLING **********************/
  489.  
  490. static void DrawBlock(LONG x,LONG y,LONG mapx,LONG mapy)
  491. {
  492.     UBYTE block;
  493.  
  494.     // x = in pixels
  495.     // y = in "planelines" (1 realline = BLOCKSDEPTH planelines)
  496.  
  497.     x = (x / 8) & 0xFFFE;
  498.     
  499.     block = mapdata[mapy * mapwidth + mapx];
  500.  
  501.     mapx = (block % BLOCKSPERROW) * (BLOCKWIDTH / 8);
  502.     mapy = (block / BLOCKSPERROW) * (BLOCKPLANELINES * BLOCKSBYTESPERROW);
  503.     
  504.     if (option_how) OwnBlitter();
  505.  
  506.     if (y + BLOCKPLANELINES <= BITMAPPLANELINES)
  507.     {
  508.         // blit does not cross bitmap's bottom boundary
  509.         
  510.         HardWaitBlit();
  511.         
  512.         custom->bltcon0 = 0x9F0;    // use A and D. Op: D = A
  513.         custom->bltcon1 = 0;
  514.         custom->bltafwm = 0xFFFF;
  515.         custom->bltalwm = 0xFFFF;
  516.         custom->bltamod = BLOCKSBYTESPERROW - (BLOCKWIDTH / 8);
  517.         custom->bltdmod = BITMAPBYTESPERROW - (BLOCKWIDTH / 8);
  518.         custom->bltapt  = blocksbuffer + mapy + mapx;
  519.         custom->bltdpt     = frontbuffer + y * BITMAPBYTESPERROW + x;
  520.         
  521.         custom->bltsize = BLOCKPLANELINES * 64 + (BLOCKWIDTH / 16);
  522.     } else {
  523.         // blit does cross bitmap's bottom boundary
  524.         // --> need to split blit = do two blit operations
  525.         
  526.         HardWaitBlit();
  527.         
  528.         custom->bltcon0 = 0x9F0;    // use A and D. Op: D = A
  529.         custom->bltcon1 = 0;
  530.         custom->bltafwm = 0xFFFF;
  531.         custom->bltalwm = 0xFFFF;
  532.         custom->bltamod = BLOCKSBYTESPERROW - (BLOCKWIDTH / 8);
  533.         custom->bltdmod = BITMAPBYTESPERROW - (BLOCKWIDTH / 8);
  534.         custom->bltapt  = blocksbuffer + mapy + mapx;
  535.         custom->bltdpt     = frontbuffer + y * BITMAPBYTESPERROW + x;
  536.         
  537.         y = BITMAPPLANELINES - y;
  538.         custom->bltsize = y * 64 + (BLOCKWIDTH / 16);
  539.         
  540.         HardWaitBlit();
  541.  
  542.         custom->bltdpt  = frontbuffer + x;
  543.         custom->bltsize = (BLOCKPLANELINES - y)  * 64 + (BLOCKWIDTH / 16);
  544.  
  545.     }
  546.  
  547.     if (option_how) DisownBlitter();
  548. }
  549.  
  550. static void FillScreen(void)
  551. {
  552.     WORD a,b,x,y;
  553.     
  554.     for (b = 0;b < BITMAPBLOCKSPERCOL;b++)
  555.     {
  556.         for (a = 0;a < BITMAPBLOCKSPERROW;a++)
  557.         {
  558.             x = a * BLOCKWIDTH;
  559.             y = b * BLOCKPLANELINES;
  560.  
  561.             DrawBlock(x,y,a,b);
  562.         }
  563.     }
  564. }
  565.  
  566. static void ScrollUp(void)
  567. {
  568.     WORD mapx,mapy,x,y;
  569.  
  570.     if (mapposy < 1) return;
  571.  
  572.     mapposy--;
  573.     mapblocky = mapposy / BLOCKHEIGHT;
  574.     stepy = mapposy & (NUMSTEPS_Y - 1);
  575.     
  576.     videoposy -= BLOCKSDEPTH;
  577.     if (videoposy < 0) videoposy += BITMAPPLANELINES;
  578.     if (stepy == (NUMSTEPS_Y - 1))
  579.     {
  580.         block_videoposy -= BLOCKPLANELINES;
  581.         if (block_videoposy < 0) block_videoposy += BITMAPPLANELINES;
  582.     }
  583.     
  584.     if (stepy == (NUMSTEPS_Y - 1))
  585.     {
  586.         // a complete row is filled up
  587.         // : the next fill up row will be BLOCKHEIGHT (16)
  588.         // pixels at the top, so we have to adjust
  589.         // the fillup column (for x scrolling), but
  590.         // only if the fillup column (x) contains some
  591.         // fill up blocks
  592.         
  593.         if (stepx)
  594.         {
  595.             // step 1: blit the 1st block in the fillup
  596.             //         col (x). There can only be 0 or
  597.             //         (2 or more) fill up blocks in the
  598.             //         actual implementation, so we do
  599.             //         not need to check previous_xdirection
  600.             //         for this blit
  601.             
  602.             mapx = mapblockx + BITMAPBLOCKSPERROW;
  603.             mapy = mapblocky + 1;
  604.             
  605.             x = ROUND2BLOCKWIDTH(videoposx);
  606.             y = (block_videoposy + 1 + BLOCKPLANELINES) % BITMAPPLANELINES;
  607.             
  608.             DrawBlock(x,y,mapx,mapy);
  609.             
  610.             // step 2: remove the (former) bottommost fill up
  611.             // block
  612.             
  613.             if (previous_xdirection == DIRECTION_RIGHT)
  614.             {
  615.                 *savewordpointer = saveword;
  616.             }
  617.             
  618.             mapy = stepx + 2;
  619.  
  620.             // we blit a 'left' block
  621.  
  622.             y = (block_videoposy + (mapy * BLOCKPLANELINES)) % BITMAPPLANELINES;
  623.             
  624.             savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  625.             saveword = *savewordpointer;
  626.  
  627.             mapx -= BITMAPBLOCKSPERROW;
  628.             mapy += mapblocky;
  629.  
  630.             DrawBlock(x,y,mapx,mapy);
  631.             
  632.             previous_xdirection = DIRECTION_LEFT;
  633.  
  634.         } /* if (stepx) */
  635.         
  636.     } /* if (stepy == NUMSTEPS_Y - 1) */
  637.  
  638.  
  639.     mapx = stepy;
  640.     mapy = mapblocky;
  641.     
  642.     y = block_videoposy;
  643.  
  644.    if (mapx >= TWOBLOCKSTEP)
  645.    {
  646.        // blit only one block
  647.        
  648.        mapx += TWOBLOCKSTEP;
  649.  
  650.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  651.  
  652.         ADJUSTDESTCOORDS(x,y)
  653.  
  654.        mapx += mapblockx;
  655.  
  656.        DrawBlock(x,y,mapx,mapy);
  657.        
  658.    } else {
  659.        // blit two blocks
  660.        
  661.        mapx *= 2;
  662.  
  663.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  664.  
  665.         ADJUSTDESTCOORDS(x,y)
  666.  
  667.         mapx += mapblockx;
  668.  
  669.        DrawBlock(x,y,mapx,mapy);
  670.        
  671.        x += BLOCKWIDTH;
  672.  
  673.         ADJUSTDESTCOORDS(x,y)
  674.  
  675.        DrawBlock(x,y,mapx + 1,mapy);
  676.        
  677.    }
  678. }
  679.  
  680. static void ScrollDown(void)
  681. {
  682.     WORD mapx,mapy,x,y,y2;
  683.  
  684.     if (mapposy >= (mapheight * BLOCKHEIGHT - SCREENHEIGHT - BLOCKHEIGHT)) return;
  685.     
  686.     mapx = stepy;
  687.     mapy = mapblocky + BITMAPBLOCKSPERCOL;
  688.     
  689.     y = block_videoposy;
  690.  
  691.    if (mapx >= TWOBLOCKSTEP)
  692.    {
  693.        // blit only one block
  694.        
  695.        mapx += TWOBLOCKSTEP;
  696.  
  697.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  698.  
  699.         ADJUSTDESTCOORDS(x,y)
  700.  
  701.        mapx += mapblockx;
  702.  
  703.        DrawBlock(x,y,mapx,mapy);
  704.        
  705.    } else {
  706.        // blit two blocks
  707.        
  708.        mapx *= 2;
  709.  
  710.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  711.  
  712.         ADJUSTDESTCOORDS(x,y)
  713.  
  714.        mapx += mapblockx;
  715.        
  716.        DrawBlock(x,y,mapx,mapy);
  717.        
  718.        x += BLOCKWIDTH;
  719.  
  720.         ADJUSTDESTCOORDS(x,y)
  721.  
  722.        DrawBlock(x,y,mapx + 1,mapy);
  723.    }
  724.  
  725.     mapposy++;
  726.     mapblocky = mapposy / BLOCKHEIGHT;
  727.     stepy = mapposy & (NUMSTEPS_Y - 1);
  728.     
  729.     videoposy += BLOCKSDEPTH;
  730.     if (videoposy >= BITMAPPLANELINES) videoposy -= BITMAPPLANELINES;
  731.     
  732.     if (!stepy)
  733.     {
  734.         block_videoposy += BLOCKPLANELINES;
  735.         if (block_videoposy >= BITMAPPLANELINES) block_videoposy -= BITMAPPLANELINES;
  736.     }
  737.  
  738.     if (stepy == 0)
  739.     {
  740.         // a complete row is filled up
  741.         // : the next fill up row will be BLOCKHEIGHT (16)
  742.         // pixels at the bottom, so we have to adjust
  743.         // the fillup column (for x scrolling), but
  744.         // only if the fillup column (x) contains some
  745.         // fill up blocks
  746.         
  747.         if (stepx)
  748.         {
  749.             // step 1: blit the 1st block in the fillup
  750.             //         row (y) because this block must
  751.             //         not be part of the fillup col (x)
  752.             //         instead it is for exclusive use
  753.             //         by the fillup row
  754.             
  755.             mapx = mapblockx;
  756.             mapy = mapblocky;
  757.             
  758.             x = ROUND2BLOCKWIDTH(videoposx);
  759.             y = block_videoposy;
  760.             
  761.             DrawBlock(x,y,mapx,mapy);
  762.             
  763.             // step 2: blit the (new) bottommost fill up
  764.             // block
  765.             
  766.             if (previous_xdirection == DIRECTION_LEFT)
  767.             {
  768.                 *savewordpointer = saveword;
  769.             }
  770.             
  771.             mapy = stepx + 1;
  772.  
  773.             // we blit a 'right' block, therefore + 1
  774.  
  775.             y = (block_videoposy + 1 + (mapy * BLOCKPLANELINES)) % BITMAPPLANELINES;
  776.             y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  777.             
  778.             savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + (x / 8));
  779.             saveword = *savewordpointer;
  780.  
  781.             mapx += BITMAPBLOCKSPERROW;
  782.             mapy += mapblocky;
  783.  
  784.             DrawBlock(x,y,mapx,mapy);
  785.             
  786.             previous_xdirection = DIRECTION_RIGHT;
  787.         } /* if (stepx) */
  788.         
  789.     } /* if (stepy == 0) */
  790.     
  791.  
  792. }
  793.  
  794. static void ScrollLeft(void)
  795. {
  796.     WORD mapx,mapy,x,y;
  797.     
  798.     if (mapposx < 1) return;
  799.     
  800.     mapposx--;
  801.     mapblockx = mapposx / BLOCKWIDTH;
  802.     stepx = mapposx & (NUMSTEPS_X - 1);
  803.  
  804.     videoposx--;
  805.     if (videoposx < 0)
  806.     {
  807.         videoposx = BITMAPWIDTH - 1;
  808.  
  809.         videoposy--;
  810.         if (videoposy < 0) videoposy = BITMAPPLANELINES - 1;
  811.  
  812.         block_videoposy--;
  813.         if (block_videoposy < 0) block_videoposy = BITMAPPLANELINES - 1;
  814.     }
  815.     
  816.     //
  817.  
  818.     if (stepx == (NUMSTEPS_X - 1))
  819.     {
  820.         // a complete column is filled up
  821.         // : the next fill up column will be BLOCKWIDTH (16)
  822.         // pixels at the left, so we have to adjust
  823.         // the fillup row (for y scrolling)
  824.         
  825.         // step 1: blit the block which came in at
  826.         //         the left side and which might or
  827.         //         might not be a fill up block
  828.         
  829.         mapx = mapblockx;
  830.         mapy = mapblocky;
  831.         if (stepy)
  832.         {
  833.             // there is a fill up block
  834.             // so block which comes in left is
  835.             // a fillup block
  836.             
  837.             mapy += BITMAPBLOCKSPERCOL;
  838.         }
  839.  
  840.         x = ROUND2BLOCKWIDTH(videoposx);
  841.         y = block_videoposy;
  842.         
  843.         DrawBlock(x,y,mapx,mapy);
  844.         
  845.         // step 2: remove the (former) rightmost fillup-block
  846.         
  847.         mapx = stepy;
  848.         if (mapx)
  849.         {
  850.             // there is a fill up block;
  851.             
  852.             if (mapx >= TWOBLOCKSTEP)
  853.             {
  854.                 mapx += TWOBLOCKSTEP;
  855.             } else {
  856.                 mapx *= 2;
  857.             }
  858.                         
  859.             x = ROUND2BLOCKWIDTH(videoposx) + (mapx * BLOCKWIDTH);
  860.             y = block_videoposy;
  861.             
  862.             ADJUSTDESTCOORDS(x,y)
  863.  
  864.             mapx += mapblockx;
  865.             mapy -= BITMAPBLOCKSPERCOL;
  866.             DrawBlock(x,y,mapx,mapy);
  867.         }
  868.  
  869.     }
  870.  
  871.  
  872.     mapx = mapblockx;
  873.     mapy = stepx + 1;
  874.  
  875.     x = ROUND2BLOCKWIDTH(videoposx);
  876.     
  877.     if (previous_xdirection == DIRECTION_RIGHT)
  878.     {
  879.         HardWaitBlit();
  880.         *savewordpointer = saveword;
  881.     }
  882.  
  883.     if (mapy == 1)
  884.     {
  885.         // blit two blocks
  886.  
  887.         mapy += mapblocky;
  888.         
  889.         y = (block_videoposy + (1 * BLOCKPLANELINES)) % BITMAPPLANELINES;
  890.  
  891.         savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  892.         saveword = *savewordpointer;
  893.         
  894.         DrawBlock(x,y,mapx,mapy);
  895.         
  896.         y = (y + BLOCKPLANELINES) % BITMAPPLANELINES;
  897.  
  898.         DrawBlock(x,y,mapx,mapy + 1);
  899.  
  900.     } else {
  901.         // blit one block
  902.  
  903.         mapy ++;
  904.         
  905.         y = (block_videoposy + (mapy * BLOCKPLANELINES)) % BITMAPPLANELINES;
  906.         
  907.         mapy += mapblocky;
  908.  
  909.         savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  910.         saveword = *savewordpointer;
  911.  
  912.         DrawBlock(x,y,mapx,mapy);
  913.     }
  914.     
  915.     if (stepx)
  916.     {
  917.         previous_xdirection = DIRECTION_LEFT;
  918.     } else {
  919.         previous_xdirection = DIRECTION_IGNORE;
  920.     }
  921. }
  922.  
  923. static void ScrollRight(void)
  924. {
  925.     WORD mapx,mapy,x,y,y2;
  926.     
  927.     if (mapposx >= (mapwidth * BLOCKWIDTH - SCREENWIDTH - BLOCKWIDTH)) return;
  928.  
  929.     mapx = mapblockx + BITMAPBLOCKSPERROW;
  930.     mapy = stepx + 1;
  931.  
  932.     x = ROUND2BLOCKWIDTH(videoposx);
  933.     
  934.     if (previous_xdirection == DIRECTION_LEFT)
  935.     {
  936.         HardWaitBlit();
  937.         *savewordpointer = saveword;
  938.     }
  939.  
  940.     if (mapy == 1)
  941.     {
  942.         // blit two blocks
  943.  
  944.         mapy += mapblocky;
  945.         
  946.         y = (block_videoposy + 1 + (1 * BLOCKPLANELINES)) % BITMAPPLANELINES;
  947.         
  948.         DrawBlock(x,y,mapx,mapy);
  949.         
  950.         y = (y + BLOCKPLANELINES) % BITMAPPLANELINES;
  951.         y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  952.         
  953.         savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + (x / 8));
  954.         saveword = *savewordpointer;
  955.  
  956.         DrawBlock(x,y,mapx,mapy + 1);
  957.  
  958.     } else {
  959.         // blit one block
  960.  
  961.         mapy ++;
  962.         
  963.         y = (block_videoposy + 1 + (mapy * BLOCKPLANELINES)) % BITMAPPLANELINES;
  964.         y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  965.         
  966.         mapy += mapblocky;
  967.  
  968.         savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + (x / 8));
  969.         saveword = *savewordpointer;
  970.  
  971.         DrawBlock(x,y,mapx,mapy);
  972.     }
  973.     
  974.     //
  975.     
  976.     mapposx++;
  977.     mapblockx = mapposx / BLOCKWIDTH;
  978.     stepx = mapposx & (NUMSTEPS_X - 1);
  979.  
  980.     videoposx++;
  981.     if (videoposx == BITMAPWIDTH)
  982.     {
  983.         videoposx = 0;
  984.  
  985.         videoposy++;
  986.         if (videoposy == BITMAPPLANELINES) videoposy = 0;
  987.  
  988.         block_videoposy++;
  989.         if (block_videoposy == BITMAPPLANELINES) block_videoposy = 0;
  990.     }
  991.     
  992.     if (stepx == 0)
  993.     {
  994.         // a complete column is filled up
  995.         // : the next fill up column will be BLOCKWIDTH (16)
  996.         // pixels at the right, so we have to adjust
  997.         // the fillup row (for y scrolling)
  998.         
  999.         // step 1: blit the block which came in at
  1000.         //         the right side and which is never
  1001.         //         a fill up block
  1002.         
  1003.         mapx = mapblockx + BITMAPBLOCKSPERROW - 1;
  1004.         mapy = mapblocky;
  1005.         
  1006.         x = ROUND2BLOCKWIDTH(videoposx) + (BITMAPBLOCKSPERROW - 1) * BLOCKWIDTH;
  1007.         y = block_videoposy;
  1008.         
  1009.         ADJUSTDESTCOORDS(x,y)
  1010.         
  1011.         DrawBlock(x,y,mapx,mapy);
  1012.         
  1013.         // step 2: blit the (new) rightmost fillup-block
  1014.         
  1015.         mapx = stepy;
  1016.         if (mapx)
  1017.         {
  1018.             // there is a fill up block;
  1019.             
  1020.             if (mapx >= TWOBLOCKSTEP)
  1021.             {
  1022.                 mapx += (TWOBLOCKSTEP - 1);
  1023.             } else {
  1024.                 mapx = mapx * 2 - 1;
  1025.             }
  1026.                         
  1027.             x = ROUND2BLOCKWIDTH(videoposx) + (mapx * BLOCKWIDTH);
  1028.             y = block_videoposy;
  1029.             
  1030.             ADJUSTDESTCOORDS(x,y)
  1031.  
  1032.             mapx += mapblockx;
  1033.  
  1034.             DrawBlock(x,y,mapx,mapy + BITMAPBLOCKSPERCOL);
  1035.         }
  1036.     }
  1037.  
  1038.     if (stepx)
  1039.     {
  1040.         previous_xdirection = DIRECTION_RIGHT;
  1041.     } else {
  1042.         previous_xdirection = DIRECTION_IGNORE;
  1043.     }
  1044. }
  1045.  
  1046. static void CheckJoyScroll(void)
  1047. {
  1048.     WORD i,count;
  1049.     
  1050.     if (JoyFire()) count = 4; else count = 1;
  1051.  
  1052.     if (JoyUp())
  1053.     {
  1054.         for(i = 0;i < count;i++)
  1055.         {
  1056.             ScrollUp();
  1057.         }
  1058.     }
  1059.     
  1060.     if (JoyDown())
  1061.     {
  1062.         for(i = 0;i < count;i++)
  1063.         {
  1064.             ScrollDown();
  1065.         }
  1066.     }
  1067.  
  1068.     if (JoyLeft())
  1069.     {
  1070.         for(i = 0;i < count;i++)
  1071.         {
  1072.             ScrollLeft();
  1073.         }
  1074.     }
  1075.     
  1076.     if (JoyRight())
  1077.     {
  1078.         for(i = 0;i < count;i++)
  1079.         {
  1080.             ScrollRight();
  1081.         }
  1082.     }
  1083.  
  1084. }
  1085.  
  1086. static void BlitVideoSplitLine(void)
  1087. {
  1088.     WORD x,y,bytes;
  1089.  
  1090.     y = videoposy % BLOCKSDEPTH;
  1091.     x = videoposx;
  1092.     
  1093.     bytes = y * BITMAPBYTESPERROW + (x / 8);
  1094.  
  1095.     if (bytes >= 2)
  1096.     {
  1097.         HardWaitBlit();
  1098.         
  1099.         custom->bltcon0 = 0x9F0;
  1100.         custom->bltcon1 = 0;
  1101.         custom->bltafwm = 0xFFFF;
  1102.         custom->bltalwm = 0xFFFF;
  1103.         custom->bltamod = 0;
  1104.         custom->bltdmod = 0;
  1105.         custom->bltapt  = frontbuffer;
  1106.         custom->bltdpt  = frontbuffer + BITMAPPLANELINES * BITMAPBYTESPERROW;
  1107.  
  1108.         custom->bltsize = (bytes / 2) * 64 + 1;
  1109.     }
  1110. }
  1111.  
  1112. static void UpdateCopperlist(void)
  1113. {
  1114.     ULONG pl;
  1115.     LONG    planeadd,planeaddx;
  1116.     WORD    i,xpos,scroll,yoffset;
  1117.     WORD    *wp;
  1118.  
  1119.     i = fetchinfo[option_fetchmode].scrollpixels;
  1120.  
  1121.     xpos = videoposx + i - 1;
  1122.  
  1123.     planeaddx = (xpos / i) * (i / 8);
  1124.     i = (i - 1) - (xpos & (i - 1));
  1125.     
  1126.     scroll = (i & 15) * 0x11;
  1127.     if (i & 16) scroll |= (0x400 + 0x4000);
  1128.     if (i & 32) scroll |= (0x800 + 0x8000);
  1129.     
  1130.     // set scroll register in BPLCON1
  1131.     
  1132.     CopBPLCON1[1] = scroll;
  1133.  
  1134.     // set top plane pointers
  1135.  
  1136.     // yoffset is in planelines!!! not reallines!
  1137.  
  1138.     yoffset = (videoposy + BLOCKHEIGHT * BLOCKSDEPTH) % BITMAPPLANELINES;
  1139.     planeadd = ((LONG)yoffset) * BITMAPBYTESPERROW;
  1140.     
  1141.     wp = CopPLANE1H;
  1142.  
  1143.     for(i = 0;i < BLOCKSDEPTH;i++)
  1144.     {
  1145.         pl = ((ULONG)ScreenBitmap->Planes[i]) + planeadd + planeaddx;
  1146.         
  1147.         wp[1] = (WORD)(pl >> 16);
  1148.         wp[3] = (WORD)(pl & 0xFFFF);
  1149.         
  1150.         wp += 4;
  1151.     }
  1152.  
  1153.     // set video split wait
  1154.  
  1155.     yoffset = yoffset / BLOCKSDEPTH;    // convert planelines to splitlines
  1156.  
  1157.     yoffset = BITMAPHEIGHT - yoffset;
  1158.     yoffset += (DIWSTART >> 8);
  1159.  
  1160.     /* CopVIDEOSPLIT must wait for line (yoffset -1 )
  1161.        CopVIDEOSPLIT2 must wait for line (yoffset)    */
  1162.  
  1163.     if (yoffset <= 255)
  1164.     {
  1165.         CopVIDEOSPLIT[0] = 0x0001;
  1166.         CopVIDEOSPLIT[2] = (yoffset - 1) * 256 + 0x1;
  1167.  
  1168.         CopVIDEOSPLIT2[0] = 0x0001;
  1169.         CopVIDEOSPLIT2[2] = yoffset * 256 + 0x1;
  1170.     } else if (yoffset == 256)
  1171.     {
  1172.         CopVIDEOSPLIT[0] = 0x0001;
  1173.         CopVIDEOSPLIT[2] = 255 * 256 + 0x1;
  1174.         
  1175.         CopVIDEOSPLIT2[0] = 0xFFDF;
  1176.         CopVIDEOSPLIT2[2] = (256 - 256) * 256 + 0x1;
  1177.     } else {
  1178.         CopVIDEOSPLIT[0] = 0xFFDF;
  1179.         CopVIDEOSPLIT[2] = (yoffset - 256 - 1) * 256 + 0x1;
  1180.         
  1181.         CopVIDEOSPLIT2[0] = 0x001;
  1182.         CopVIDEOSPLIT2[2] = (yoffset - 256) * 256 + 0x1;
  1183.     }
  1184.  
  1185.     /* Set video split plane pointers (to top of bitmap):
  1186.  
  1187.          We only set the hiwords. The lowords are automatically
  1188.          correct thanks to the modulo-trick in the copperlist
  1189.          which is setup in UpdateCopperlist().
  1190.     */
  1191.     
  1192.     pl = (ULONG)ScreenBitmap->Planes[0] +
  1193.           planeaddx +
  1194.          (videoposy % BLOCKSDEPTH) * BITMAPBYTESPERROW;
  1195.  
  1196.     // set high words
  1197.  
  1198.     wp = CopPLANE2_1H;
  1199.     
  1200.     for(i = 0;i < BLOCKSDEPTH;i++)
  1201.     {
  1202.         wp[1] = (WORD)(pl >> 16);
  1203.  
  1204.         pl += BITMAPBYTESPERROW * BLOCKSDEPTH;
  1205.         wp += 2;
  1206.     }
  1207.  
  1208. }
  1209.  
  1210. static void MainLoop(void)
  1211. {
  1212.     if (!option_how)
  1213.     {
  1214.         // activate copperlist
  1215.         
  1216.         HardWaitBlit();
  1217.         WaitVBL();
  1218.  
  1219.         custom->copjmp2 = 0;
  1220.     }
  1221.     
  1222.     while (!LMBDown())
  1223.     {
  1224.         if (!option_how)
  1225.         {
  1226.             WaitVBeam(1);
  1227.             UpdateCopperlist();
  1228.             WaitVBeam(200);
  1229.         } else {
  1230.             Delay(1);
  1231.         }
  1232.  
  1233.         if (option_speed) *(WORD *)0xdff180 = 0xFF0;
  1234.         
  1235.         CheckJoyScroll();
  1236.         BlitVideoSplitLine();
  1237.  
  1238.         if (option_speed) *(WORD *)0xdff180 = 0xF00;
  1239.     }
  1240. }
  1241.  
  1242. /********************* MAIN *************************/
  1243.  
  1244. void main(void)
  1245. {
  1246.     OpenLibs();
  1247.     GetArguments();
  1248.     OpenMap();
  1249.     OpenBlocks();
  1250.     OpenDisplay();
  1251.  
  1252.     if (!option_how)
  1253.     {
  1254.         Delay(2*50);
  1255.         KillSystem();
  1256.         InitCopperlist();
  1257.     }
  1258.     FillScreen();
  1259.     
  1260.     MainLoop();
  1261.     
  1262.     if (!option_how)
  1263.     {
  1264.         ActivateSystem();
  1265.     }
  1266.  
  1267.     Cleanup(0);
  1268.     
  1269. }
  1270.  
  1271.